import ElemMovable from './ElemMovable.js';

export default class PanelFolder {
  constructor(target, options) {
    let opt = {
      folderMovable: true,
      foldTo: 'topRight',
      buttonText: '展开',
      buttonStyle: {},
      getPosition: null,
      getContainer: null,
      onExpand: null,
      onFold: null,
      onMoveEnd: null,
    };
    let foldToEnum = {
      topLeft: {
        fold: 'translate(-50%, -50%) scale(0,0)',
        expand: 'translate(0, 0) scale(1,1)',
        getPosition: (el, style, buttonStyle) => ({
          top: style.y,
          left: style.x,
        }),
      },
      topRight: {
        fold: 'translate(50%, -50%) scale(0,0)',
        expand: 'translate(0, 0) scale(1,1)',
        getPosition: (el, style, buttonStyle) => ({
          top: style.y,
          right: style.right,
        }),
      },
      bottomLeft: {
        fold: 'translate(-50%, 50%) scale(0,0)',
        expand: 'translate(0, 0) scale(1,1)',
        getPosition: (el, style, buttonStyle) => ({
          top: style.y + style.height - parseFloat(buttonStyle.height),
          left: style.x,
        }),
      },
      bottomRight: {
        fold: 'translate(50%, 50%) scale(0,0)',
        expand: 'translate(0, 0) scale(1,1)',
        getPosition: (el, style, buttonStyle) => ({
          top: style.y + style.height - parseFloat(buttonStyle.height),
          left: style.x + style.width - parseFloat(buttonStyle.width),
        }),
      },
      topCenter: {
        fold: 'translate(0, -50%) scale(0,0)',
        expand: 'translate(0, 0) scale(1,1)',
        getPosition: (el, style, buttonStyle) => ({
          top: style.y,
          left: style.x + style.width / 2 - parseFloat(buttonStyle.width),
        }),
      },
      rightCenter: {
        fold: 'translate(50%, 0) scale(0,0)',
        expand: 'translate(0, 0) scale(1,1)',
        getPosition: (el, style, buttonStyle) => ({
          top: style.y + style.height / 2 - parseFloat(buttonStyle.height) / 2,
          left: style.x + style.width - parseFloat(buttonStyle.width),
        }),
      },
      bottomCenter: {
        fold: 'translate(0, 50%) scale(0,0)',
        expand: 'translate(0, 0) scale(1,1)',
        getPosition: (el, style, buttonStyle) => ({
          top: style.y + style.height - parseFloat(buttonStyle.height),
          left: style.x + style.width / 2 - parseFloat(buttonStyle.width) / 2,
        }),
      },
      leftCenter: {
        fold: 'translate(-50%, 0) scale(0,0)',
        expand: 'translate(0, 0) scale(1,1)',
        getPosition: (el, style, buttonStyle) => ({
          top: style.y + style.height / 2 - parseFloat(buttonStyle.height) / 2,
          left: style.x,
        }),
      },
      center: {
        fold: 'translate(0, 0) scale(0,0)',
        expand: 'translate(0, 0) scale(1,1)',
        getPosition: (el, style, buttonStyle) => ({
          top: style.y + style.height / 2 - parseFloat(buttonStyle.height) / 2,
          left: style.x + style.width / 2 - parseFloat(buttonStyle.width) / 2,
        }),
      },
    };
    let defaultButtonStyle = {
      position: 'fixed',
      display: 'flex',
      flexWrap: 'wrap',
      justifyContent: 'center',
      alignItems: 'center',
      width: '50px',
      height: '50px',
      background: '#fff',
      borderRadius: '6px',
      boxShadow: 'rgba(0,0,0,0.1) 0 0 9px 0px',
      zIndex: 9999,
      cursor: 'pointer',
    };
    let option = Object.assign({}, opt, options);
    let getHook = (option, name, defaultHook) => {
      return typeof option[name] === 'function' ? option[name] : defaultHook;
    };
    let getSnakeCase = (str) => {
      return str.replace(/[A-Z]/g, ($0) => '-' + String.prototype.toLocaleLowerCase.call($0));
    };
    let getCssText = (style) => {
      return Object.keys(style).reduce((res, key) => {
        return res + (getSnakeCase(key) + ': ' + style[key] + ';');
      }, ';');
    };
    let getFoldOption = (key) => {
      return (foldToEnum[option.foldTo] || foldToEnum[opt.foldTo])[key];
    };
    let getPosition = getHook(option, 'getPosition', getFoldOption('getPosition'));
    let getContainer = getHook(option, 'getContainer', () => document.body);
    let onExpand = getHook(option, 'onExpand', () => {});
    let onFold = getHook(option, 'onFold', () => {});

    let el, bcr, buttonStyle, elemMovable;
    el = document.createElement('div');
    el.title = '双击展开';
    el.innerHTML = option.buttonText || opt.buttonText;
    el.ondblclick = () => this.expand();
    if (option.folderMovable === true) {
      elemMovable = new ElemMovable({
        anchor: el,
        target: el,
        getPosition: getPosition,
        onMoveEnd: getHook(option, 'onMoveEnd'),
      });
    }
    if (typeof option.buttonStyle === 'function') {
      buttonStyle = option.buttonStyle(Object.assign({}, defaultButtonStyle));
    } else {
      buttonStyle = Object.assign({}, defaultButtonStyle, option.buttonStyle);
    }

    this.fold = () => {
      let winW, winH, style, container;
      winW = window.innerWidth;
      winH = window.innerHeight;
      container = getContainer();
      bcr = target.getBoundingClientRect();
      bcr = {
        winW: winW,
        winH: winH,
        x: bcr.x,
        y: bcr.y,
        width: bcr.width,
        height: bcr.height,
        top: bcr.top,
        right: winW - bcr.right,
        bottom: winH - bcr.bottom,
        left: bcr.left,
      };
      style = getPosition(target, bcr, buttonStyle);
      style = Object.assign({}, buttonStyle, style);
      ['top', 'right', 'bottom', 'left'].forEach((key) => {
        if (typeof style[key] === 'number') style[key] += 'px';
      });
      if (!el.parentElement || el.parentElement !== container) {
        container.appendChild(el);
      }
      el.style.cssText = getCssText(style);
      target.style.transition = 'transform ease 0.3s';
      target.style.transform = getFoldOption('fold');
    };
    this.expand = () => {
      if (el.parentElement) {
        el.parentElement.removeChild(el);
      }
      target.style.transition = 'transform ease 0.3s';
      target.style.transform = getFoldOption('expand');
    };
    this.destroy = () => {
      if (el.parentElement) {
        el.parentElement.removeChild(el);
      }
      elemMovable.destroy();
      elemMovable = null;
      option = null;
      opt = null;
      el = null;
      bcr = null;
      getHook = null;
      getCssText = null;
      getSnakeCase = null;
      getContainer = null;
      getPosition = null;
      onExpand = null;
      onFold = null;
      foldToEnum = null;
      buttonStyle = null;
      defaultButtonStyle = null;
    };
  }
}
